/*
 * lcd_display.c
 *
 *  Created on: 2024年9月16日
 *      Author: LeiWang
 */


#include "lcd_display.h"
#include "lcd_font.h"

// 使用spi向lcd发送数据
void lcd_spi_write(uint8_t data){
    lcd_cs_clr();
    HAL_SPI_Transmit(&LCD_SPI_HANDLE,&data,1,0xFFFF);
    lcd_cs_set();
}
// 向lcd写命令
void lcd_write_cmd(uint8_t cmd){
    lcd_dc_clr();
    lcd_spi_write(cmd);
}

// 向lcd写8位数据
void lcd_write_data8(uint16_t dat){
    lcd_dc_set();
    lcd_spi_write(dat);
}

// 向lcd写16位数据
void lcd_write_data(uint16_t dat){
    lcd_dc_set();
    lcd_spi_write(dat>>8);
    lcd_spi_write(dat);
}

// 设置绘图窗口
void lcd_address_set(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1){
    
    if(USE_HORIZONTAL == 0){
        lcd_write_cmd(0x2A);        // 列地址设置
        lcd_write_data8((x0+35)>>8);
        lcd_write_data8(x0+35);
        lcd_write_data8((x1+35)>>8);
        lcd_write_data8(x1+35);
        lcd_write_cmd(0x2B);        // 行地址设置
        lcd_write_data(y0);
        lcd_write_data(y1);
        lcd_write_cmd(0x2C);        // 储存器写
    }
    else if(USE_HORIZONTAL == 1){
        lcd_write_cmd(0x2A);        // 列地址设置
        lcd_write_data(x0+35);
        lcd_write_data(x1+35);
        lcd_write_cmd(0x2B);        // 行地址设置
        lcd_write_data(y0);
        lcd_write_data(y1);
        lcd_write_cmd(0x2C);        // 储存器写
    }
    else if(USE_HORIZONTAL == 2){
        lcd_write_cmd(0x2A);        // 列地址设置
        lcd_write_data(x0);
        lcd_write_data(x1);
        lcd_write_cmd(0x2B);        // 行地址设置
        lcd_write_data(y0+35);
        lcd_write_data(y1+35);
        lcd_write_cmd(0x2C);        // 储存器写
    }
    else {
        lcd_write_cmd(0x2A);        // 列地址设置
        lcd_write_data(x0);
        lcd_write_data(x1);
        lcd_write_cmd(0x2B);        // 行地址设置
        lcd_write_data(y0+35);
        lcd_write_data(y1+35);
        lcd_write_cmd(0x2C);        // 储存器写
    }
}

// lcd初始化
void lcd_init(){
    // 复位lcd
    lcd_res_clr();
    HAL_Delay(30);
    lcd_res_set();
    HAL_Delay(100);
    
    // 打开背光
    
    HAL_Delay(100);
    
    // 启动lcd
    lcd_write_cmd(0x11);
    //HAL_Delay(120);
    lcd_write_cmd(0x36);
    if(USE_HORIZONTAL==0)lcd_write_data8(0x00);
    else if(USE_HORIZONTAL==1)lcd_write_data8(0xC0);
    else if(USE_HORIZONTAL==2)lcd_write_data8(0x70);
    else lcd_write_data8(0xA0);
    
    lcd_write_cmd(0x3A);
    lcd_write_data8(0x05);

    lcd_write_cmd(0xB2);
    lcd_write_data8(0x0C);
    lcd_write_data8(0x0C);
    lcd_write_data8(0x00);
    lcd_write_data8(0x33);
    lcd_write_data8(0x33); 

    lcd_write_cmd(0xB7); 
    lcd_write_data8(0x35);  

    lcd_write_cmd(0xBB);
    lcd_write_data8(0x1A);

    lcd_write_cmd(0xC0);
    lcd_write_data8(0x2C);

    lcd_write_cmd(0xC2);
    lcd_write_data8(0x01);

    lcd_write_cmd(0xC3);
    lcd_write_data8(0x0B);   

    lcd_write_cmd(0xC4);
    lcd_write_data8(0x20);  

    lcd_write_cmd(0xC6); 
    lcd_write_data8(0x0F);    

    lcd_write_cmd(0xD0); 
    lcd_write_data8(0xA4);
    lcd_write_data8(0xA1);

    lcd_write_cmd(0x21); 
    lcd_write_cmd(0xE0);
    lcd_write_data8(0xF0);
    lcd_write_data8(0x00);
    lcd_write_data8(0x04);
    lcd_write_data8(0x04);
    lcd_write_data8(0x04);
    lcd_write_data8(0x05);
    lcd_write_data8(0x29);
    lcd_write_data8(0x33);
    lcd_write_data8(0x3E);
    lcd_write_data8(0x38);
    lcd_write_data8(0x12);
    lcd_write_data8(0x12);
    lcd_write_data8(0x28);
    lcd_write_data8(0x30);

    lcd_write_cmd(0xE1);
    lcd_write_data8(0xF0);
    lcd_write_data8(0x07);
    lcd_write_data8(0x0A);
    lcd_write_data8(0x0D);
    lcd_write_data8(0x0B);
    lcd_write_data8(0x07);
    lcd_write_data8(0x28);
    lcd_write_data8(0x33);
    lcd_write_data8(0x3E);
    lcd_write_data8(0x36);
    lcd_write_data8(0x14);
    lcd_write_data8(0x14);
    lcd_write_data8(0x29);
    lcd_write_data8(0x32);

    lcd_write_cmd(0x11);
    HAL_Delay(120);
    lcd_write_cmd(0x29);
}
// lcd绘制一个像素
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
{
    if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT))
        return;  // 坐标超出范围

    lcd_address_set(x, y, x + 1, y + 1);
    lcd_write_data8(color >> 8);
    lcd_write_data8(color & 0xFF);
}

// lcd填充屏幕
void lcd_fill_screen(uint16_t color)
{
    lcd_address_set(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1);
    for (uint32_t i = 0; i < LCD_WIDTH * LCD_HEIGHT; i++)
    {
        lcd_write_data8(color >> 8);
        lcd_write_data8(color & 0xFF);
    }
}

// lcd画线
void lcd_draw_line(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t color)
{
    int16_t dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
    int16_t dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1; 
    int16_t err = dx + dy, e2; /* error value e_xy */

    while (1)
    {
        lcd_draw_point(x0, y0, color); // 画一个点

        if (x0 == x1 && y0 == y1)
            break;

        e2 = 2 * err;
        if (e2 >= dy)
        {
            err += dy;
            x0 += sx;
        } 
        if (e2 <= dx)
        {
            err += dx;
            y0 += sy;
        }
    }
}

// lcd绘制矩形（Bresenham算法）
void lcd_draw_rectangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,uint16_t color)
{
    lcd_draw_line(x0,y0,x1,y0,color);
    lcd_draw_line(x0,y0,x0,y1,color);
    lcd_draw_line(x0,y1,x1,y1,color);
    lcd_draw_line(x1,y0,x1,y1,color);
}

// lcd绘制圆形 (中点圆算法)
void lcd_draw_circle(uint16_t x0, uint16_t y0, uint16_t radius, uint16_t color)
{
    int16_t x = radius;
    int16_t y = 0;
    int16_t err = 0;

    while (x >= y)
    {
        // 使用对称性来绘制圆周上的八个点
        lcd_draw_point(x0 + x, y0 + y, color);
        lcd_draw_point(x0 + y, y0 + x, color);
        lcd_draw_point(x0 - y, y0 + x, color);
        lcd_draw_point(x0 - x, y0 + y, color);
        lcd_draw_point(x0 - x, y0 - y, color);
        lcd_draw_point(x0 - y, y0 - x, color);
        lcd_draw_point(x0 + y, y0 - x, color);
        lcd_draw_point(x0 + x, y0 - y, color);

        if (err <= 0)
        {
            y += 1;
            err += 2 * y + 1;
        }
        if (err > 0)
        {
            x -= 1;
            err -= 2 * x + 1;
        }
    }
}

// lcd显示单个字符函数
void lcd_show_char(uint16_t x, uint16_t y, uint8_t ch, uint16_t text_color, uint16_t bg_color,uint8_t sizey,uint8_t mode)
{
    uint8_t temp,sizex,t,m=0;
    uint16_t i,TypefaceNum;//一个字符所占字节大小
    uint16_t x0=x;
    sizex=sizey/2;
    TypefaceNum=(sizex/8+((sizex%8)?1:0))*sizey;
    ch=ch-' ';    //得到偏移后的值
    lcd_address_set(x,y,x+sizex-1,y+sizey-1);  //设置光标位置 
    for(i=0;i<TypefaceNum;i++)
    { 
        if(sizey==12)temp=ascii_1206[ch][i];            //调用6x12字体
        else if(sizey==16)temp=ascii_1608[ch][i];       //调用8x16字体
        else if(sizey==24)temp=ascii_2412[ch][i];       //调用12x24字体
        else if(sizey==32)temp=ascii_3216[ch][i];       //调用16x32字体
        else return;
        for(t=0;t<8;t++)
        {
            if(!mode)//非叠加模式
            {
                if(temp&(0x01<<t))lcd_write_data(text_color);
                else lcd_write_data(text_color);
                m++;
                if(m%sizex==0)
                {
                    m=0;
                    break;
                }
            }
            else//叠加模式
            {
                if(temp&(0x01<<t))lcd_draw_point(x,y,text_color);//画一个点
                x++;
                if((x-x0)==sizex)
                {
                    x=x0;
                    y++;
                    break;
                }
            }
        }
    }
}
// lcd显示字符串
void lcd_show_string(uint16_t x,uint16_t y,const uint8_t *p,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{         
    while(*p!='\0')
    {       
        lcd_show_char(x,y,*p,fc,bc,sizey,mode);
        x+=sizey/2;
        p++;
    }  
}

// lcd显示整形数字
uint32_t mypow(uint8_t m,uint8_t n)
{
    uint32_t result=1;
    while(n--)result*=m;
    return result;
}
void lcd_show_int(uint16_t x,uint16_t y,uint16_t num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey)
{         
    uint8_t t,temp;
    uint8_t enshow=0;
    uint8_t sizex=sizey/2;
    for(t=0;t<len;t++)
    {
        temp=(num/mypow(10,len-t-1))%10;
        if(enshow==0&&t<(len-1))
        {
            if(temp==0)
            {
                lcd_show_char(x+t*sizex,y,' ',fc,bc,sizey,1);
                continue;
            }else enshow=1; 
        }
        lcd_show_char(x+t*sizex,y,temp+48,fc,bc,sizey,1);
    }
} 

// lcd显示浮点数
void lcd_show_float(uint16_t x,uint16_t y,float num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey)
{
    uint8_t t,temp,sizex;
    uint16_t num1;
    sizex=sizey/2;
    num1=num*100;
    for(t=0;t<len;t++)
    {
        temp=(num1/mypow(10,len-t-1))%10;
        if(t==(len-2))
        {
            lcd_show_char(x+(len-2)*sizex,y,'.',fc,bc,sizey,1);
            t++;
            len+=1;
        }
        lcd_show_char(x+t*sizex,y,temp+48,fc,bc,sizey,1);
    }
}

// lcd显示图片
void lcd_show_picture(uint16_t x0, uint16_t y0, uint16_t width, uint16_t height, const uint8_t pic[])
{
    lcd_address_set(x0, y0, x0 + width - 1, y0 + height - 1);       // 设置绘图窗口

    uint32_t pixelCount = width * height;       // 每个像素是16位(RGB565格式)

    // 发送图片数据
    lcd_dc_set();
    lcd_cs_clr();
    HAL_SPI_Transmit(&hspi1, (uint8_t *)pic, pixelCount * 2, HAL_MAX_DELAY);  // 每个像素2字节
    lcd_cs_set();
}
